package com.hqyj.springbootdemo01.user.controller;

import com.hqyj.springbootdemo01.common.result.Result;
import com.hqyj.springbootdemo01.common.utils.RedisUtils;
import com.hqyj.springbootdemo01.user.dto.UserInfo;
import com.hqyj.springbootdemo01.user.entity.User;
import com.hqyj.springbootdemo01.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

/**
 * redis操作类
 * @author sdx2009
 * @package com.hqyj.springbootdemo01.user.controller
 * @date 2022/9/2 16:47
 */
@RestController
@RequestMapping("/api/redis")
@Slf4j
public class RedisController {

    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private UserService userService;

    @GetMapping("/string")
    public Result<?> setString() {
        redisUtils.set("userName", "zhangsan");
        redisUtils.setEx("password", "123456", 30);

        String userName = redisUtils.get("userName").toString();
        String password = redisUtils.get("password").toString();

        log.info("userName={},password={}", userName, password);

        return new Result<>().success();
    }

    @GetMapping("/map")
    public Result<?> setMap() {
        Map<String, Object> map = new HashMap<>();
        map.put("userName", "zhangsan");
//      把map对象存入redis，第一个参数是map对象在redis中的键值
        redisUtils.hmset("mapkey", map);

//        把key为password，value为123456的键值对存到redis的map中
//        相当于先把password，123456存到map（map.put("password","123456")），然后再把map存到redis中
        redisUtils.hset("mapkey", "password", "123456");

//        获取整个map对象
        Map<Object, Object> resultMap = redisUtils.hmget("mapkey");

        log.info("resultMap = {}", resultMap);

//        相当于先通过mapkey获取到map
//        然后再从map中根据userName获取到value值（zhangsan）
        String userName = redisUtils.hget("mapkey", "userName").toString();

        log.info("userName = {}", userName);

//        带过期时间的hmset方法
        redisUtils.hmset("mapkey1", map, 20);

//        带过期时间的hset方法
        redisUtils.hset("mapkey2", "password", "123", 20);

//        删除
        redisUtils.hdel("mapkey", "userName", "password");


        return new Result<>().success();
    }

    @GetMapping("/set")
    public Result<?> opsSet() {

//        添加set集合的数据到redis
        redisUtils.sSet("setkey", "zhangsan", "lisi", "wangwu");

//        获取set集合
        Set<Object> resultSet = redisUtils.sGet("setkey");
        log.info("set = {}", resultSet);

//        查询指定的value值是否在set集合内
        boolean resultHasKey = redisUtils.sHasKey("setkey", "xiaoming");
        log.info("haskey = {}", resultHasKey);

//        添加带过期时间的集合数据到redis
        redisUtils.sSetAndTime("setkey1", 20, "xiaoming");

//        获取set集合的长度
        long setSize = redisUtils.sGetSetSize("setkey");
        log.info("set size = {}", setSize);

//        删除set集合中的value
        redisUtils.setRemove("setkey", "zhangsan");

        return new Result<>().success();
    }

    @GetMapping("/list")
    public Result<?> opsList() {

//        把value添加到list中，并保存到redis
//        redisUtils.lSet("listkey", "zhangsan");

//        把value添加到list，并保存到redis，带有过期时间
//        redisUtils.lSet("listkey1", "zhangsan", 20);

//        将list对象保存到redis中
//        List<String> list = new ArrayList<>();
//        list.add("lisi");
//        list.add("wangwu");
//        redisUtils.lSet("listkey", list);

//        将list对象保存在redis中，带有过期时间
//        redisUtils.lSet("listkey1", list, 20);

//        通过指定的下标index修改list中的值
//        redisUtils.lUpdateIndex("listkey", 0, "lisi");

//        删除指定值
//        redisUtils.lRemove("listkey", 3, "zhangsan");
//
//        redisUtils.lRemove("listkey", 3, list);

//        获取list对象
        List<Object> resultList = redisUtils.lGet("listkey", 0, -1);
        log.info("resultList={}", resultList);

//        获取list的长度
        long listSize = redisUtils.lGetListSize("listkey");
        log.info("list size={}", listSize);

//        根据指定的index下标获取list中的value值
//        index>=0，是按照下标值获取
//        index<0,从list的尾部开始获取，比如：index=-1，获取list最后一个元素，index=-2获取list倒数第二个元素，以此类推
        String value = redisUtils.lGetIndex("listkey", 0).toString();
        log.info("value={}", value);

        Object obj = redisUtils.lGetIndex("listkey", -2);
        log.info("obj = {}", obj);

        return new Result<>().success();
    }

    /**
     * Cacheable一般用在查询方法上
     * 当接收请求后，先到redis中查询，如果redis有数据则直接返回
     * 如果redis中没有数据，则执行方法中的查询逻辑，获取查询结果
     * 然后把结果存入redis缓存中
     *
     * 应用场景：
     * 数据变化不太频繁，每次查询都是相同的结果
     *
     * @param userName
     * @return
     */
    @GetMapping("/userInfo")
    @Cacheable(value = "user")
    public Result<?> userInfo(String userName) {
        User user = userService.getUserInfoByName(userName);
        if (Objects.isNull(user)) {
            return new Result<>().error();
        }
        return new Result<>().success().put(user);
    }

    /**
     * 一般用在add或者update方法上
     * 不管redis是否存在数据，每次执行方法都会重新存入redis
     *
     * @param userInfo
     * @return
     */
    @GetMapping("/addUser")
    @CachePut(value = "user", key = "#userInfo.userName")
    public Result<?> addUser(UserInfo userInfo) {
        boolean result = userService.addUser(userInfo);
        if (result) {
            return new Result<>().success();
        } else {
            return new Result<>().error();
        }
    }

    /**
     * 一般用在删除方法上
     * 当方法执行时会把redis缓存中对应的数据（value值）删除掉
     *
     * @param id
     * @return
     */
    @GetMapping("/deleteUser")
    @CacheEvict(value = "user", allEntries = true)
    public Result<?> deleteUser(Integer id) {
        boolean result = userService.deleteUser(id);
        if (result) {
            return new Result<>().success();
        } else {
            return new Result<>().error();
        }
    }
}
